package model;

import java.awt.Toolkit;
import java.util.Scanner;

import apps.AppReg;

/**
 * Stores and handles all the lengths within an SVG file.
 */
public class Length {
    public static final String LENGTH_UNITS_REGEX = "(em|ex|px|in|cm|mm|pt|pc|%)";
    public static final String LENGTH_REGEX = "^[+-]?[0-9]+\\.?([0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)?$";
    public static final String LENGTH_NO_UNITS = "(no units)";

    private String lenghtStr;
    private double number;
    private String units;

    public static int lengthX; // Used for percentage
    public static int lengthY; // Used for percentage

    private Orientation percentOrien;

    public enum Orientation {
	X, Y
    }

    /**
     * Constructs a Length with length = 0
     */
    public Length() {
	setToZero();
    }

    /**
     * Constructs a new Length based on the lengthStr provided
     * 
     * @param lengthStr
     *            supplied String is parsed and Length created from it
     */
    public Length(String lengthStr) {
	this.update(lengthStr);
    }

    // Used for percentages, we need a number to base from
    public Length(String lengthStr, Orientation percentOrien) {
	this.update(lengthStr);
	this.percentOrien = percentOrien;
    }

    private void setToZero() {
	this.lenghtStr = "0";
	this.number = 0.0;
	this.units = LENGTH_NO_UNITS;
    }

    /** Supplied String is parsed and used to update Length
     * @param lengthStr
     */
    public void update(String lengthStr) {
	this.lenghtStr = lengthStr;

	if (lengthStr.matches("^none$")) {
	    setToZero();
	    this.lenghtStr = lengthStr;
	    return;
	}

	if (!lengthStr.matches(LENGTH_REGEX)) {
	    System.err.println("The Length " + lengthStr + " is imparsible");
	} else {

	    Scanner sc = new Scanner(lengthStr);
	    sc.useDelimiter(LENGTH_UNITS_REGEX);
	    if (sc.hasNext()) {
		number = sc.nextDouble();
		sc.reset();
		if (sc.hasNext())
		    units = sc.next();
		else
		    units = LENGTH_NO_UNITS;
	    }
	}
    }

    public String getLenghtStr() {
	return lenghtStr;
    }

    public double getNumber() {
	return number;
    }

    public String getUnits() {
	return units;
    }

    public String debugString() {
	return String.format("%-10s->\t%f\t%s", lenghtStr, number, units);
    }

    public static double getNumber(String lengthStr) {
	return new Length(lengthStr).getNumber();
    }

    public static String getUnits(String lengthStr) {
	return new Length(lengthStr).getUnits();
    }

    // Does what the fuckin title says
    public int getCmToPixels(double cm) {

	// Grab the toolkit object
	Toolkit toolk;
	toolk = AppReg.getFrame().getToolkit();

	// Get the number of pixels in an inch
	int dpi = toolk.getScreenResolution();

	// Calc pixels in a centimeter
	double pixelsPerCM = dpi / 2.54;

	return (int) (cm * pixelsPerCM);
    }

    public int getPointsToPixels(double points) {
	// Grab the toolkit object
	Toolkit toolk;
	toolk = AppReg.getFrame().getToolkit();

	// Get the number of pixels in an inch
	int dpi = toolk.getScreenResolution();

	return (int) (points / dpi);
    }

    public int getMmToPixels(double mm) {

	// Grab the toolkit object
	Toolkit toolk;
	toolk = AppReg.getFrame().getToolkit();

	// Get the number of pixels in an inch
	int dpi = toolk.getScreenResolution();

	// Calc pixels in a mm
	double pixelsPerMM = dpi / 2.54 / 10;

	return (int) (mm * pixelsPerMM);
    }

    public int getInchesToPixels(double inches) {

	// Grab the toolkit object
	Toolkit toolk;
	toolk = AppReg.getFrame().getToolkit();

	// Get the number of pixels in an inch
	int dpi = toolk.getScreenResolution();

	// Calc pixels in a mm
	double pixelsPerInch = dpi;

	return (int) (inches * pixelsPerInch);
    }

    public int getEmToPixels(double ems) {
	// Get font height - should be 12
	int em = AppReg.getFrame().getFont().getSize();

	// Return em into pixels
	return (int) (ems * em);
    }

    public int getPcToPixels(double pc) {
	// Return em into pixels
	return (int) (pc * 16);
    }

    // horW = height or width of orignal SVG
    @SuppressWarnings("static-access")
    public int getPercentToPixels(double percent) {
	// Put it into a scale where 1 = 100%
	float scale = (float) getNumber() / 100;
	int converted = 0;

	switch (this.percentOrien) {
	case X:
	    converted = (int) (this.lengthX * scale);
	    break;

	case Y:
	    converted = (int) (this.lengthY * scale);
	    break;
	}

	return converted;

    }

    public int getInPixels() {

	int converted = 0;

	// If error
	if (getUnits() == null)
	    return 0;

	if (getUnits().equals("(no units)")) {
	    return (int) getNumber();
	} else if (getUnits().equals("px")) {
	    // parse it in inches
	    return (int) getNumber();
	} else if (getUnits().equals("pc")) {
	    // Pass it the inches to convert
	    converted = getPcToPixels(getNumber());
	} else if (getUnits().equals("in")) {
	    // Pass it the inches to convert
	    converted = getInchesToPixels(getNumber());
	} else if (getUnits().equals("em") || getUnits().equals("ex")) {
	    // Pass it the em/ex to convert
	    converted = getEmToPixels(getNumber());
	} else if (getUnits().equals("cm")) {
	    // Pass it the centimertes to convert
	    converted = getCmToPixels(getNumber());
	} else if (getUnits().equals("mm")) {
	    // Pass it the mm to convert
	    converted = getMmToPixels(getNumber());
	} else if (getUnits().equals("pt")) {
	    // Pass it the points(dpi) to convert
	    converted = getPointsToPixels(getNumber());
	} else if (getUnits().equals("%")) {
	    // Pass it the percent as a number
	    converted = getPercentToPixels(getNumber());

	} else
	    System.out.println(getUnits() + " Not convertible yet");

	return converted;

    }

    /**
     * Tests Length class
     * 
     * @param args not used
     *            
     */
    public static void main(String[] args) {
	String[] lenghtTest = { "none", "0", "0.0", "000", "1", "10", "50",
		"100", "1.2", "10.25", "50.33", "100.00", "1cm", "10em",
		"50pt", "100pc", "1.2cm", "10.25em", "50.33pt", "100.00pc",
		"8%", "8.0%", "80%", "80.0%", "100%", "100.0%" };

	Length length = new Length();

	for (String len : lenghtTest) {
	    length.update(len);
	    System.out.println(length.debugString());
	}
    }
}
